package main

import (
	"fmt"
	"io/ioutil"
	. "luago/api"
	"luago/binchunk"
	"luago/state"
	"os"

	_ "luago/binchunk"
	"luago/vm"
)

func main() {
	if len(os.Args) > 1 {
		data, err := ioutil.ReadFile(os.Args[1])
		if err != nil {
			panic(err)
		}

		proto := binchunk.Undump(data)
		luaMain(proto)
	}
}

func luaMain(proto *binchunk.Prototype) {
	nRegs := int(proto.MaxStackSize)
	ls := state.New(nRegs+8, proto)
	ls.SetTop(nRegs)
	for {
		pc := ls.PC()
		inst := vm.Instruction(ls.Fetch())
		if inst.Opcode() != vm.OP_RETURN {
			inst.Execute(ls)

			fmt.Printf("[%02d] %s ", pc+1, inst.OpName())
			printStack(ls)
		} else {
			break
		}
	}
}

func printStack(ls LuaState) {
	top := ls.GetTop()
	for i := 1; i <= top; i++ {
		t := ls.Type(i)
		switch t {
		case LUA_TBOOLEAN:
			fmt.Printf("[%t]", ls.ToBoolean(i))
		case LUA_TNUMBER:
			fmt.Printf("[%g]", ls.ToNumber(i))
		case LUA_TSTRING:
			fmt.Printf("[%q]", ls.ToString(i))
		default: // other values
			fmt.Printf("[%s]", ls.TypeName(t))
		}
	}
	fmt.Println()
}

//第五章

// func main() {
// 	ls := state.New()
// 	ls.PushInteger(1)
// 	ls.PushString("2.0")
// 	ls.PushString("3.0")
// 	ls.PushNumber(4.0)
// 	printStack(ls)

// 	ls.Arith(LUA_OPADD)
// 	printStack(ls)
// 	ls.Arith(LUA_OPBNOT)
// 	printStack(ls)
// 	ls.Len(2)
// 	printStack(ls)
// 	ls.Concat(3)
// 	printStack(ls)
// 	ls.PushBoolean(ls.Compare(1, 2, LUA_OPEQ))
// 	printStack(ls)
// }

// func printStack(ls LuaState) {
// 	top := ls.GetTop()
// 	for i := 1; i <= top; i++ {
// 		t := ls.Type(i)
// 		switch t {
// 		case LUA_TBOOLEAN:
// 			fmt.Printf("[%t]", ls.ToBoolean(i))
// 		case LUA_TNUMBER:
// 			fmt.Printf("[%g]", ls.ToNumber(i))
// 		case LUA_TSTRING:
// 			fmt.Printf("[%q]", ls.ToString(i))
// 		default: // other values
// 			fmt.Printf("[%s]", ls.TypeName(t))
// 		}
// 	}
// 	fmt.Println()
// }
